<?php

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 * Description of BusquedaTabu
 *
 * @author Marlon
 */
require('MemoriaTabu.php');
class BusquedaTabu {
    //put your code here
    private $MatrizTrabaxPedido=array();
    private $MemoriaT;
    private $Iteracciones;
    private $CordenasTrab=array();
    private $CostoActual=0;
    function __construct($ite,$lonMemo,$permanencia) {
        $this->MemoriaT=new  MemoriaTabu();
        $this->Iteracciones=$ite;
        $this->MemoriaT->SetLong($lonMemo);
        $this->MemoriaT->SetPermanencia($permanencia);
    }
    public function SetMatriTrabxPed($matrizTrabPed){
        $this->MatrizTrabaxPedido=$matrizTrabPed;
    }
    public function GetMatriTrabxPed(){
        return $this->MatrizTrabaxPedido;
    }
     public function SetCosto($cost){
        $this->CostoActual=$cost;
    }
    public function GetCasto(){
        return $this->CostoActual;
    }    
    public function buscarCordenadas($matriz){
        //
        if(count($matriz)!=0){
            $fil=0;
            foreach($matriz as $matrizTrabPed){
               $col=0;
                foreach($matrizTrabPed as $TrabxPedi){
                  
                    array_push($this->CordenasTrab, array('col'=>$col,'fil'=>$fil));                    
                    $col++;
                }
                $fil++;
            }
           
        } 
    }
    
   public function intercambio(&$anterior,&$posterior){//se realiza el intercambio de las fecha de inicio y culminacion
       $curretnCulAnt=strtotime($anterior['C']);
       $curretnIniAnt=strtotime($anterior['Ini']);
       $rangTrabAnte=$curretnCulAnt-$curretnIniAnt;
       $curretnCulPost=strtotime($posterior['C']);
       $curretnIniPost=strtotime($posterior['Ini']);
       $rangTrabPost=$curretnCulPost-$curretnIniPost;
       $this->mueveBloque($anterior,$rangTrabPost);
       $this->mueveBloque($posterior,(-1*$rangTrabAnte));
       	$temp = $anterior;
        $anterior = $posterior;
        $posterior = $temp;
   }
    public function funObjetivo($matriz){//Esta matriz sera bidimensional conteniendo 
    //los trabajos por cada pedido los valores de Importancia(w), Fecha Culminacion(C), Fecha de Entrega del pedido(d)
        $resultado=0;
        if(count($matriz)!=0){
            foreach($matriz as $matrizTrabPed){
                foreach($matrizTrabPed as $TrabxPedi){
                    $curretnCul=strtotime($TrabxPedi['C']);
                    $curretnEnt=strtotime($TrabxPedi['d']);
                    $horas=($curretnCul-$curretnEnt)/ 60/ 60;
                    $resultado+=max(($TrabxPedi['w']*($horas)),0);
                }
            }
        }        
        return $resultado;
    }
     public function mueveBloque(&$trabajo,$movida){//si movida es positivo avanza si es negativo retrocede           
         
         $trabajo['C']=date('Y-m-d',(strtotime($trabajo['C'])+$movida));
         $trabajo['Ini']=date('Y-m-d',(strtotime($trabajo['Ini'])+$movida)); 
        
     }
     public function moverFechas(&$Trabajos,$desde,$numDias){
         for($m=$desde;$m<count($Trabajos);$m++){
            $this->mueveBloque($Trabajos[$m], $numDias);
           
         }
     }
     public function correPredescesoras(&$Trabajos,$fil,$col){
         $coorPred=$Trabajos[$fil][$col]['Pred'];
         $diaCAnt=strtotime($Matriz[$fil][$col]['C']);
         $diaIPost=strtotime($Matriz[$fil][$col+1]['Ini']);
         $numDias=$diaIPost-$diaCAnt;
         if($numDias!=0){
             if($coorPred['fil']!=-1){
             $this->moverFechas($Trabajos[$fil],$col,$numDias);
             $this->correPredescesoras($Trabajos,$coorPred['fil'],$coorPred['col']);
         }
            else return 1;
         } else return 1;         
     }
     public function correTodo(&$Trabajos,$fil,$col){
         //primero se corre las antescesoras y luego las predescesoras
         
        
         if(isset($Trabajos[$fil][$col]['Antec'])){
             $coorAnt=$Trabajos[$fil][$col]['Antec'];
             if($coorAnt['fil']!=-1){
             if($col>0){
                 $dif=strtotime($Trabajos[$fil][$col]['Ini'])-strtotime(date('Y-m-d'));//se verifica que eexista diferencia entre la fecha actual y la de iniciailizacion
                 if($dif>0){
                     $this->moverFechas($Trabajos[$fil],$col,(-1*$dif));//se retrocede todos los trabajos
                     $this->correTodo($Trabajos,$coorAnt['fil'],$coorAnt['col']);
                 } else if($dif<0){
                     $this->intercambio($Trabajos[$fil][$col-1],$Trabajos[$fil][$col]);//se retrocede todos los trabajos
                     $this->correTodo($Trabajos,$coorAnt['fil'],$coorAnt['col']);
                 }
             } else return 1;
         }
         else {           
             if((count($Trabajos[$fil])-1)>$col){//verifica que $col no sea el utimo elemento de la fila
                 $this->correPredescesoras($Trabajos,$fil,$col);
               }
             }
         }
                  
     }
     public function realizaMovimiento(&$Matriz,$col,$fil){      
         $this->intercambio($Matriz[$fil][intval($col)-1], $Matriz[$fil][$col]);
         //se verificara si afecto a los trabajos de la fila
         if((count($Matriz[$fil])-1)>$col){//verifica que $col no sea el utimo elemento de la fila        
             $this->correTodo($Matriz,$fil,$col+1);             
         }
     }
     public function indiceMenorValor($valInicial,$valores){
         $result=-1;$menoVal=$valInicial;
        
         for($i=0;$i<count($valores);$i++){
             if($valores[$i]<$menoVal){
                 $result=$i;
                 $menoVal=$valores[$i];
             }
         }
      
         return $result;
     }
     public function BusquedaTabu(){
         $minVal=  $this->funObjetivo($this->MatrizTrabaxPedido);
         $matrizAux=$this->MatrizTrabaxPedido;
         $lamejor=array();
         $this->buscarCordenadas($matrizAux);//forma las coordenada de los posibles movimeintos a realizar
         
         for($m=0;$m<$this->Iteracciones;$m++){
            if(count($this->CordenasTrab)!=0){
                $valoresFo=array();$matrices=array();$movimiento=array();
                foreach($this->CordenasTrab as $corrMov){
                    $aux=$matrizAux;
                    $mov=array('col'=>$corrMov['col'],'fil'=>$corrMov['fil']);
               
                    if(intval($corrMov['col'])-1>0){//si existe mas de 2 elementos en la fila
                        if(!$this->MemoriaT->existeMov($mov)){//si existe el movimiento este no se realiza  
                                
                                $this->realizaMovimiento($aux, $corrMov['col'], $corrMov['fil']);
                                $fo=  $this->funObjetivo($aux);
                                array_push($valoresFo,$fo);
                                array_push($matrices,$aux);
                                array_push($movimiento,$mov);
                                unset($aux); 
                            }
                                           
                    } 
                }
                if(count($matrices)>0){//si se tiene varios movimientos realizados
                   
                    $indice=  $this->indiceMenorValor($minVal, $valoresFo);
                    if($indice!=-1){
                        $minVal=$valoresFo[$indice];
                        $lamejor=$matrices[$indice];//si el valor es menor o igual se considerea coo una mejor solucion              
                        $matrizAux=$lamejor;
                        $this->MemoriaT->reducirPermanencia();//reduce el tiempo de permanencia de los demas
                        $this->MemoriaT->agregarMov($movimiento[$indice]);
                    } else {
                        //se seguira con el minimo valor del arreglo manteniendo el valor minimo actual
                        $minimo=min($valoresFo);
                        //huscando el indice
                        for($k=0;$k<count($valoresFo);$k++){
                            if($minimo==$valoresFo[$k]) break;
                        }
                        $matrizAux=$matrices[$k];//se toma $k            
                        $this->MemoriaT->reducirPermanencia();//reduce el tiempo de permanencia de los demas
                        $this->MemoriaT->agregarMov($movimiento[$k]);
                    }                    
                }
                
            }
            else break;
         }
         if(count($lamejor)!=0)
            $this->SetMatriTrabxPed($lamejor);
     }
    
}

?>
